package com.spsoft.vatoutinv.service.vmsfullbswjmanager.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.core.config.VmsCommonProperties;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.mapper.VmsFullBswjManagerMapper;
import com.spsoft.vatoutinv.model.dto.vmsfullbswjmanager.VmsFullVswjManagerPageDto;
import com.spsoft.vatoutinv.model.vo.vmsfullbswjmanager.VmsFullBswjManagerDetailVO;
import com.spsoft.vatoutinv.model.vo.vmsfullbswjmanager.VmsFullBswjManagerKprVO;
import com.spsoft.vatoutinv.model.vo.vmsfullbswjmanager.VmsFullBswjManagerPageVO;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 数电发票板式文件管理表;数电发票板式文件管理表 服务实现类
 * </p>
 *
 * @author wangy
 * @since 2023-11-29
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class VmsFullBswjManagerServiceImpl extends ServiceImpl<VmsFullBswjManagerMapper, VmsFullBswjManager> implements VmsFullBswjManagerService {

    private final VmsCommonProperties vmsProperties;

    private final RedisService redisService;

    @Override
    public Result<IPage<VmsFullBswjManagerPageVO>> getPage(VmsFullVswjManagerPageDto dto) {
        Integer pageNo = dto.getPageNo();
        Integer pageSize = dto.getPageSize();
        LambdaQueryWrapper<VmsFullBswjManager> lq = new LambdaQueryWrapper<VmsFullBswjManager>().likeRight(StringUtil.isNotEmpty(dto.getNsztName()), VmsFullBswjManager::getNsztName, dto.getNsztName()).likeRight(StringUtil.isNotEmpty(dto.getNsrsbh()), VmsFullBswjManager::getNsrsbh, dto.getNsrsbh()).eq(StringUtil.isNotEmpty(dto.getBswjsczt()), VmsFullBswjManager::getBswjsczt, dto.getBswjsczt()).eq(StringUtil.isNotEmpty(dto.getFpkjzt()), VmsFullBswjManager::getFpkjzt, dto.getFpkjzt()).orderByDesc(VmsFullBswjManager::getWhsj);
        IPage<VmsFullBswjManagerPageVO> page = this.page(new Page<>(pageNo, pageSize), lq).convert(item -> {
            VmsFullBswjManagerPageVO vo = new VmsFullBswjManagerPageVO();
            BeanUtils.copyBeanProp(vo, item);
            int lastIndex = item.getQzzpdz().lastIndexOf('/');
            String fileName = item.getQzzpdz().substring(lastIndex + 1);
            vo.setQzzpdz(fileName);
            return vo;
        });
        return Result.OK(page);
    }

    @Override
    @Transactional
    public Result<Long> fileSave(MultipartFile multipartFile, String deptCode, String qydm, String qymc, String ptbh, String bswjsczt, String fpkjzt, String bswjId, String nsrsbh, String nsrmc, String jkkpkpr) {
        Long l = handleVmsFullBswjManager(deptCode, multipartFile, bswjId, qydm, qymc, ptbh, bswjsczt, fpkjzt, jkkpkpr, nsrmc, nsrsbh);
        return Result.OK(l);
    }

    public String filePath(String deptCode) {
        VmsFullBswjManager one = getOneByWhjg(deptCode);
        if (ObjectUtil.isNotEmpty(one)) {
            return vmsProperties.filePath() + one.getQzzpdz();
        } else {
            throw new BusinessException(ResponseEnum.LAYOUT_FILE_NOT_FOUND);
        }
    }

    @Override
    public Result<String> getFileById(String id) {
        VmsFullBswjManager entity = getById(id);
        if (ObjectUtil.isEmpty(entity) || StringUtil.isEmpty(entity.getQzzpdz())) {
            throw new BusinessException(ResponseEnum.IMAGE_FILE_NOT_FIND);
        }
        String path = vmsProperties.filePath() + entity.getQzzpdz();
        try {
            byte[] imageBytes = Files.readAllBytes(Paths.get(path));
            return Result.OK(Base64.getEncoder().encodeToString(imageBytes));
        } catch (IOException e) {
            throw new BusinessException(ResponseEnum.IMAGE_FILE_NOT_FIND);
        }
    }

    @Override
    public Result<VmsFullBswjManager> getInfoBywhjg(String whjg) {
        return Result.OK(getOneByWhjg(whjg));
    }

    @Override
    public Result<Boolean> deleteFileById(String id) {
        // 先获取对象
        VmsFullBswjManager entity = getById(id);
        // 删除文件
        String path = vmsProperties.filePath() + entity.getQzzpdz();
        try {
            Files.delete(Paths.get(path));
        } catch (IOException e) {
            // 不处理
        }
        // 删除数据
        removeById(id);
        // 删除缓存
        String redisKey = String.format(RedisConstant.REDIS_FULL_BSWJ_CACHE_KEY, entity.getWhjg());
        redisService.deleteObject(redisKey);
        return Result.OK();
    }

    public VmsFullBswjManager getOneByWhjg(String whjg) {
        String redisKey = String.format(RedisConstant.REDIS_FULL_BSWJ_CACHE_KEY, whjg);
        String result = redisService.getCacheObject(redisKey);
        VmsFullBswjManager vmsFullBswjManager = null;
        if (StringUtils.isNotEmpty(result)) {
            vmsFullBswjManager = JSONUtil.toBean(result, VmsFullBswjManager.class);
            return vmsFullBswjManager;
        } else {
            VmsFullBswjManager one = getOne(new LambdaQueryWrapper<VmsFullBswjManager>().eq(VmsFullBswjManager::getWhjg, whjg).eq(VmsFullBswjManager::getQyzt, CommonConstant.STR_01));
            if (ObjectUtil.isNotEmpty(one)) {
                redisService.setCacheObject(redisKey, JSONUtil.toJsonStr(one));
            } else {
                throw new BusinessException(ResponseEnum.FULL_BSWJ_ERROR_01);
            }
            return one;
        }
    }

    @Override
    public Result<VmsFullBswjManagerDetailVO> getDetailByBswjId(String bswjId) {
        VmsFullBswjManager byId = getById(bswjId);
        if (ObjectUtil.isNotEmpty(byId)) {
            VmsFullBswjManagerDetailVO vo = new VmsFullBswjManagerDetailVO();
            BeanUtils.copyBeanProp(vo, byId);
            return Result.OK(vo);
        }
        return Result.ERROR();
    }

    @Override
    public Result<String> updateStatus(String id, String type, String status) {
        // type 01 版式文件  02 发票开具
        VmsFullBswjManager fullBswjManager = new VmsFullBswjManager();
        // 获取当前对象
        VmsFullBswjManager byId = getById(id);
        byId.setBswjid(byId.getBswjid());
        BeanUtils.copyBeanProp(fullBswjManager, byId);
        if ("01".equals(type)) {
            fullBswjManager.setBswjsczt(status);
        }
        if ("02".equals(type)) {
            fullBswjManager.setFpkjzt(status);
        }
        if ("03".equals(type)) {
            fullBswjManager.setQyzt(status);
        }
        boolean update = update(fullBswjManager, new LambdaQueryWrapper<VmsFullBswjManager>().eq(VmsFullBswjManager::getBswjid, id));
        if (!update) {
            return Result.ERROR(ResponseEnum.BUSINESS_SWITCH_ERROR_01);
        }
        String redisKey = String.format(RedisConstant.REDIS_FULL_BSWJ_CACHE_KEY, fullBswjManager.getWhjg());
        if ("03".equals(type) && status.equals(CommonConstant.STR_02)) {
            redisService.deleteObject(redisKey);
        } else {
            redisService.setCacheObject(redisKey, JSONUtil.toJsonStr(fullBswjManager));
        }
        return Result.OK("修改成功");
    }

    public boolean queryStatus(String deptCode, String type) {
        VmsFullBswjManager one = getOneByWhjg(deptCode);
        if (ObjectUtil.isNotEmpty(one)) {
            if (CommonEnum.BUSINESS_SWITCH_TYPE_01.getKey().equals(type)) {
                return CommonConstant.STR_Y.equals(one.getBswjsczt());
            }
            if (CommonEnum.BUSINESS_SWITCH_TYPE_02.getKey().equals(type)) {
                return CommonConstant.STR_Y.equals(one.getFpkjzt());
            }
        }
        return false;
    }

    @Override
    public List<VmsFullBswjManager> getAllSdDeptInfo() {
        LambdaQueryWrapper<VmsFullBswjManager> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VmsFullBswjManager::getQyzt, CommonConstant.STR_01);
        wrapper.orderByAsc(VmsFullBswjManager::getBswjid);
        return this.list(wrapper);
    }

    @Override
    public Result<List<VmsFullBswjManagerKprVO>> getJkkprByWhjg(String whjg) {
        return Result.OK(this.baseMapper.getJkkprByWhjg(whjg));
    }

    @Override
    @PostConstruct
    public void loadCache() {
        // 获取所有已启用数据
        List<VmsFullBswjManager> allSdDeptInfo = getAllSdDeptInfo();
        // 存入 redis 中
        allSdDeptInfo.forEach(item -> {
            String redisKey = String.format(RedisConstant.REDIS_FULL_BSWJ_CACHE_KEY, item.getWhjg());
            redisService.setCacheObject(redisKey, JSONUtil.toJsonStr(item));
        });
    }


    public Long handleVmsFullBswjManager(String deptCode, MultipartFile multipartFile, String bswjId, String qydm, String qymc,
                                         String ptbh, String bswjsczt, String fpkjzt, String jkkpkpr, String nsrmc, String nsrsbh) {
        String nsrsbhPath = nsrsbh + File.separator;
        String fileName = generateFileName(multipartFile);
        if (StringUtil.isEmpty(fileName)) {
            fileName = getOneByWhjg(deptCode).getQzzpdz();
            // 去除 纳税人识别号+ file.separator
            fileName = fileName.substring(fileName.lastIndexOf(File.separator) + 1);
        }
        // 新增或修改操作
        boolean isUpdate = StringUtil.isNotEmpty(bswjId);
        VmsFullBswjManager vmsFullBswjManager;
        if (isUpdate) {
            vmsFullBswjManager = updateExistingRecord(deptCode, bswjId, qydm, qymc, ptbh, bswjsczt, fpkjzt, jkkpkpr, nsrmc, nsrsbh, nsrsbhPath, fileName);
        } else {
            vmsFullBswjManager = createNewRecord(deptCode, qydm, qymc, ptbh, bswjsczt, fpkjzt, jkkpkpr, nsrmc, nsrsbh, nsrsbhPath, fileName);
        }

        if (ObjectUtil.isNotEmpty(multipartFile)) {
            String targetFilePathStr = buildTargetFilePath(nsrsbhPath, fileName);
            Path targetFilePath = Paths.get(targetFilePathStr);
            // 判断文件夹是否创建成功
            File targetDir = new File(targetFilePath.getParent().toString());
            if (!targetDir.exists()) {
                boolean mkdirsResult = targetDir.mkdirs();
                if (!mkdirsResult) {
                    throw new BusinessException(ResponseEnum.FILE_SAVE_ERROR_01);
                }
            }
            try (InputStream inputStream = multipartFile.getInputStream()) {
                Files.copy(inputStream, targetFilePath, StandardCopyOption.REPLACE_EXISTING);
            } catch (NoSuchFileException nsfe) {
                throw new BusinessException(ResponseEnum.FILE_SAVE_ERROR_01);
            } catch (IOException e) {
                throw new BusinessException(ResponseEnum.FILE_SAVE_ERROR);
            }
        }

        // 更新Redis缓存
        String redisKey = String.format(RedisConstant.REDIS_FULL_BSWJ_CACHE_KEY, deptCode);
        redisService.setCacheObject(redisKey, JSONUtil.toJsonStr(vmsFullBswjManager));

        return vmsFullBswjManager.getBswjid();
    }


    private String generateFileName(MultipartFile multipartFile) {
        if (ObjectUtil.isEmpty(multipartFile)) {
            return "";
        }
        String originalName = multipartFile.getOriginalFilename();
        int lastDotIndex = originalName.lastIndexOf(".");
        return UUID.randomUUID() + originalName.substring(lastDotIndex);
    }

    private String buildTargetFilePath(String nsrsbhPath, String fileName) {
        return vmsProperties.filePath() + nsrsbhPath + fileName;
    }

    private VmsFullBswjManager updateExistingRecord(String deptCode, String bswjId, String qydm, String qymc, String ptbh,
                                                    String bswjsczt, String fpkjzt, String jkkpkpr, String nsrmc, String nsrsbh, String nsrsbhPath, String fileName) {
        VmsFullBswjManager existingRecord = getById(bswjId);
        if (existingRecord == null || !existingRecord.getWhjg().equals(deptCode)) {
            throw new BusinessException(ResponseEnum.BSWJ_ERROR_01);
        }

        existingRecord.setQydm(qydm);
        existingRecord.setQymc(qymc);
        existingRecord.setSydwbh(ptbh);
        existingRecord.setBswjsczt(bswjsczt);
        existingRecord.setFpkjzt(fpkjzt);
        existingRecord.setJkkpkpr(jkkpkpr);
        existingRecord.setNsztName(nsrmc);
        existingRecord.setNsrsbh(nsrsbh);
        existingRecord.setQzzpdz(nsrsbhPath + fileName);

        boolean updateResult = updateById(existingRecord);
        if (!updateResult) {
            throw new BusinessException(ResponseEnum.DB_UPDATE_FAILED);
        }

        return existingRecord;
    }

    private VmsFullBswjManager createNewRecord(String deptCode, String qydm, String qymc, String ptbh, String bswjsczt,
                                               String fpkjzt, String jkkpkpr, String nsrmc, String nsrsbh, String nsrsbhPath, String fileName) {
        VmsFullBswjManager newRecord = new VmsFullBswjManager();
        newRecord.setBswjid(getBaseMapper().getNextSequenceValue());
        newRecord.setNsztName(nsrmc);
        newRecord.setNsrsbh(nsrsbh);
        newRecord.setQydm(qydm);
        newRecord.setQymc(qymc);
        newRecord.setQyzt(CommonConstant.STR_01);
        newRecord.setQzzpdz(nsrsbhPath + fileName);
        newRecord.setWhrmc(SecurityUtils.getUserCode());
        newRecord.setWhjg(deptCode);
        newRecord.setWhsj(new Date());
        newRecord.setSydwbh(ptbh);
        newRecord.setBswjsczt(bswjsczt);
        newRecord.setFpkjzt(fpkjzt);
        newRecord.setJkkpkpr(jkkpkpr);

        boolean saveResult = save(newRecord);
        if (!saveResult) {
            throw new BusinessException(ResponseEnum.DB_INSERT_FAILED);
        }

        return newRecord;
    }
}
